use common::error::with_context;
use rand::Rng;
use std::env;
use std::fs;
use std::fs::{create_dir, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};

pub fn setup_dir() -> Result<PathBuf, Box<dyn std::error::Error>> {
    let temp_dir = list_temp_dir()?.into_iter().find(|dir| has_identifier(dir));

    if let Some(dir) = temp_dir {
        return Ok(dir);
    }

    create_temp_dir()
}

const SELF_IDENTIFIER: &str = ".module_dev";
fn create_temp_dir() -> Result<PathBuf, Box<dyn std::error::Error>> {
    let mut rng = rand::thread_rng();
    let random_name: String = (0..10)
        .map(|_| {
            let char_range = 'a' as u32..='z' as u32;
            rng.gen_range(char_range) as u8 as char
        })
        .collect();

    let current_dir = env::current_dir()?;

    let temp_dir_path = current_dir.join(format!(".{}", random_name));

    create_dir(&temp_dir_path)?;

    let identifier_file_path = temp_dir_path.join(SELF_IDENTIFIER);
    let mut identifier_file = File::create_new(&identifier_file_path)?;
    identifier_file.write_all(b"")?;

    Ok(temp_dir_path)
}

fn has_identifier(dir: &Path) -> bool {
    let identifier_path = dir.join(SELF_IDENTIFIER);
    identifier_path.exists() && identifier_path.is_file()
}

fn list_temp_dir() -> Result<Vec<PathBuf>, Box<dyn std::error::Error>> {
    let current_dir = env::current_dir()?;
    let mut hidden_dirs = Vec::new();

    for entry in fs::read_dir(&current_dir).map_err(|err| with_context(err, "无法读取当前目录"))?
    {
        let path = entry?.path();

        if path.is_dir()
            && path
                .file_name()
                .and_then(|name| name.to_str())
                .map_or(false, |name| name.starts_with('.'))
        {
            hidden_dirs.push(path);
        }
    }

    Ok(hidden_dirs)
}
